package com.tr.rentcar.model.jdbc;

import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * 数据库操作
 * 
 * @author gson
 *
 */
public abstract class Db implements Jdbc {
	
	public <T> T queryUninResult(String sql, ParamHandler paramHandler) throws SQLException {
		return this.queryUninResult(sql, paramHandler,null);
	}

	public <T> T queryUninResult(String sql, ResultHandler<T> resultHandler) throws SQLException {
		return this.queryUninResult(sql, null, resultHandler);
	}

	/**
	 * 只返回一条结果的
	 * @param sql
	 * @param paramHandler
	 * @param resultHandler
	 * @return
	 * @throws SQLException
	 */
	public <T> T queryUninResult(String sql, ParamHandler paramHandler, ResultHandler<T> resultHandler)
			throws SQLException {
		List<T> rows = this.executeQuery(sql, paramHandler, resultHandler);
		return rows == null || rows.size() == 0 ? null : rows.get(0);
	}

	/**
	 * 不处理结果，只处理参数的查询
	 * @param sql
	 * @param paramHandler
	 * @return
	 * @throws SQLException
	 */
	public <T> List<T> executeQuery(String sql, ParamHandler paramHandler) throws SQLException {
		return this.executeQuery(sql, paramHandler, null);
	}

	/**
	 * 不处理参数，只处理结果的查询
	 * @param sql
	 * @param resultHandler
	 * @return
	 * @throws SQLException
	 */
	public <T> List<T> executeQuery(String sql, ResultHandler<T> resultHandler) throws SQLException {
		return this.executeQuery(sql, null, resultHandler);
	}

	/**
	 * 处理参数和结果的查询
	 */
	@Override
	public <T> List<T> executeQuery(String sql, ParamHandler paramHandler, ResultHandler<T> resultHandler)
			throws SQLException {
		Connection conn = null;
		PreparedStatement pst = null;
		ResultSet rs = null;
		List<T> rows = null;
		try {
			conn = geConn();
			pst = conn.prepareStatement(sql);
			// 绑定参数
			if (paramHandler != null) {
				paramHandler.doHander(pst);
			}
			rs = pst.executeQuery();
			ResultSetMetaData rsmd = pst.getMetaData();
			Map<String, Object> row;
			rows = new ArrayList<>();
			while (rs.next()) {
				row = new HashMap<>();
				for (int i = 1; i <= rsmd.getColumnCount(); i++) {
					String label = rsmd.getColumnLabel(i);
					row.put(label, rs.getObject(label));
				}
				// 处理结果
				if (resultHandler != null) {
					rows.add(resultHandler.doHander(row));
				}
			}
		} finally {
			this.release(conn, pst, rs);
		}
		return rows;
	}
	/**
	 * 处理参数的查询数目
	 * @param sql
	 * @param paramHandler
	 * @return
	 * @throws SQLException
	 */
	public Object executeCountQuery(String sql, ParamHandler paramHandler) throws SQLException{
		return this.queryUninResult(sql, paramHandler, new ResultHandler<Object>() {

			@Override
			public Object doHander(Map<String, Object> row) {
				Object obj = null;
				Set<String> set=row.keySet();
				for (String string : set) {
					obj=row.get(string);
					break;
				}
				return obj;
				
			}
		});
	}
	/**
	 * 不处理参数的查询数目
	 * @param sql
	 * @return
	 * @throws SQLException
	 */
	public Object executeCountQuery(String sql) throws SQLException{
		return this.executeCountQuery(sql,null);
	}
	

	/**
	 * 不用处理参数的更新
	 * @param sql
	 * @return
	 * @throws SQLException
	 */
	public int executeUpdate(String sql) throws SQLException {
		return this.executeUpdate(sql, null);
	}

	/**
	 * 处理参数的更新
	 */
	@Override
	public int executeUpdate(String sql, ParamHandler paramHandler) throws SQLException {
		Connection conn = null;
		PreparedStatement pst = null;
		int result = 0;
		try {
			conn = geConn();
			pst = conn.prepareStatement(sql);
			if (paramHandler != null) {
				paramHandler.doHander(pst);
			}
			result = pst.executeUpdate();
		} finally {
			this.release(conn, pst, null);
		}
		return result;
	}

	private void release(Connection conn, PreparedStatement pst, ResultSet rs) {
		try {
			if (rs != null) {
				rs.close();
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}

		try {
			if (pst != null) {
				pst.close();
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}

		try {
			if (conn != null) {
				conn.close();
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}

	public abstract Connection geConn() throws SQLException;
}
